package com.mapforge.gui.tools;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.Timer;
import javax.swing.border.BevelBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.mapforge.listener.MapToolChangeEvent;
import com.mapforge.map.tools.MapToolInterface;

/**
 * The {@link CompositeMapToolPopupButton} allows one toggle button to represent
 * many related map tools.
 * 
 * @author Will Morrison
 * 
 */
public class CompositeMapToolPopupButton extends MapToolButton {
	/**
	 * Default serial version ID, here to remove warnings.
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Popup menu displaying list of tools.
	 */
	private JPopupMenu optionsPopup;

	/**
	 * List displaying {@link MapToolInterface}
	 */
	private JList list;

	private MapToolButton[] buttons;

	/**
	 * 
	 * @param buttons
	 */
	public CompositeMapToolPopupButton(MapToolButton[] buttons) {
		super((ImageIcon) buttons[0].getIcon(), buttons[0].getMapTool(),
				buttons[0].getMapToolPanel());
		this.buttons = buttons;
		this.list = new JList(buttons);
		this.list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		this.list.addListSelectionListener(new ListListener());
		this.list.setCellRenderer(new CellRenderer());

		this.addMouseListener(new ButtonMouseListener());

		// init popup menu
		this.optionsPopup = new JPopupMenu();
		this.optionsPopup.setBorder(BorderFactory
				.createBevelBorder(BevelBorder.RAISED));
		optionsPopup.add(list);
	}

	private class ButtonMouseListener extends MouseAdapter implements
			ActionListener {
		private Timer timer;

		public ButtonMouseListener() {
			timer = new Timer(500, this);
			timer.setRepeats(false);
		}

		public void mousePressed(MouseEvent e) {
			timer.start();
		}

		public void mouseReleased(MouseEvent e) {
			timer.restart();
			timer.stop();
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			optionsPopup.show(CompositeMapToolPopupButton.this, 0, getHeight());
		}
	}

	@Override
	public void addActionListener(ActionListener listener) {
		super.addActionListener(listener);
		if (buttons != null) {
			for (MapToolButton btn : buttons) {
				btn.addActionListener(listener);
			}
		}
	}

	/**
	 * Whenever an item is selected in the list presented in our popup, close
	 * the popup, set the proper icon and tooltip in our button, and inform all
	 * listeners a new tool has been selected.
	 * 
	 * @author Will Morrison
	 * 
	 */
	private class ListListener implements ListSelectionListener {
		@Override
		public void valueChanged(ListSelectionEvent e) {
			if (!e.getValueIsAdjusting()) {
				MapToolButton btn = (MapToolButton) list.getSelectedValue();
				optionsPopup.setVisible(false);

				// copy properties from selected button
				setIcon(btn.getIcon());
				setToolTipText(btn.getMapTool().getDescription());
				setMapToolPanel(btn.getMapToolPanel());
				setMapToolCursor(btn.getMapToolCursor());
				// inform listeners this button was "clicked"
				btn.doClick();
				fireMapToolChangeEvent(new MapToolChangeEvent(
						CompositeMapToolPopupButton.this, btn.getMapTool()));
			}
		}
	}

	/**
	 * Handles rendering tool's descriptions and icons in the list displayed in
	 * our popup.
	 * 
	 * @author Will Morrison
	 * 
	 */
	private class CellRenderer implements ListCellRenderer {
		private JLabel lblStamp;

		public CellRenderer() {
			lblStamp = new JLabel();
		}

		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			MapToolButton wrap = (MapToolButton) value;
			lblStamp.setIcon(wrap.getIcon());
			lblStamp.setText(wrap.getMapTool().getDescription());
			// TODO Auto-generated method stub
			return lblStamp;
		}
	}
}
